#include "adalog/buffer/BufferPoolManager.h"
#include "adalog/buffer/ReadBufferGuard.h"
#include "adalog/buffer/WriteBufferGuard.h"

namespace adalog
{
    BufferHeader::BufferHeader(std::size_t buffer_id)
        : buffer_id_(buffer_id),
          buffer_(std::make_unique<Buffer>())
    {
    }

    const char* BufferHeader::GetDataBegin() const
    {
        return buffer_->Begin();
    }

    size_t BufferHeader::ReadableSize() const
    {
        return buffer_->ReadableSize();
    }

    void BufferHeader::WriteData(const char* data, size_t len)
    {
        buffer_->Push(data, len);
    }

    size_t BufferHeader::WritableSize() const
    {
        return buffer_->WritableSize();
    }

    void BufferHeader::Reset()
    {
        buffer_->Reset();
    }

    size_t BufferHeader::GetBufferId() const
    {
        return buffer_id_;
    }


    BufferPoolManager::BufferPoolManager(size_t num_buffer)
        : num_buffers_(num_buffer)
    {
        for (int i = 0; i < num_buffers_; ++i)
        {
            buffers_.emplace_back(std::make_shared<BufferHeader>(i));
        }
    }

    BufferPoolManager::~BufferPoolManager() {}

    size_t BufferPoolManager::Size() const
    {
        return num_buffers_;
    }

    std::optional<ReadBufferGuard> BufferPoolManager::GetReadBuffer(size_t buffer_id)
    {
        if (buffer_id >= Size())
            return std::nullopt;
        buffers_[buffer_id]->pin_count_.fetch_add(1);
        ReadBufferGuard read_guard(buffers_[buffer_id]);
        return std::move(read_guard);
    }

    std::optional<WriteBufferGuard> BufferPoolManager::GetWriteBuffer(size_t buffer_id)
    {
        if (buffer_id >= Size())
            return std::nullopt;
        buffers_[buffer_id]->pin_count_.fetch_add(1);
        WriteBufferGuard write_guard(buffers_[buffer_id]);
        return std::move(write_guard);
    }

    std::optional<size_t> BufferPoolManager::GetPinCount(size_t buffer_id)
    {
        if (buffer_id >= Size())
            return std::nullopt;
        return buffers_[buffer_id]->pin_count_;
    }

} // namespace adalog